#include <fstream>
#include <vector>
#include <sstream>

#include "Session.h"
#include "Hooks.h"
#include "WinMacroLib.h"
#include "MacroFileReader.h"


extern HINSTANCE g_hinstance;

class CPlaybackSession;

extern CPlaybackSession *g_pPlaybackSession;

using namespace std;

class CPlaybackSession : public Session
{
	std::string file_name;
	EVENTMSG previous_message;
	DWORD previous_message_play_time;

	std::vector<EVENTMSG> messages;
	DWORD message_index;
	DWORD current_repetition_index;

	PLAYBACKPROGRESSPROC playback_progress_proc;
	PLAYBACKSTOPPEDPROC playback_stopped_proc;
	PLAYBACKOPTIONS playback_options;

public:

	CPlaybackSession(LPCTSTR fileName, HINSTANCE module_instance, PLAYBACKOPTIONS playback_options, PLAYBACKSTOPPEDPROC proc, PLAYBACKPROGRESSPROC playback_progress_proc)
		: Session(module_instance), file_name(fileName), message_index(0), current_repetition_index(0)
	{
		//playlog.open("E:\\Playback.txt");
		this->playback_stopped_proc = proc;
		this->playback_progress_proc = playback_progress_proc;
		this->playback_options = playback_options;
	}

	DWORD Start()
	{
		CMacroFileReader reader;

		DWORD retVal = reader.ReadMacroFile(file_name.c_str(), messages);

		if (retVal != 0)
			return retVal;

		hook_handle = SetWindowsHookEx(WH_JOURNALPLAYBACK, JournalPlaybackProc, g_hinstance, 0);
		InstallGetMsgHook();

		if (hook_handle == NULL || getmsg_hook_handle == NULL)
		{
			DWORD error = GetLastError();
			SessionCancelled();
			return error;
		}
		else
		{
			Reinitialize();
			RaisePlaybackProgress();
			return 0;
		}
	}

	void Reinitialize()
	{
		message_index = 0;
		previous_message_play_time = start_time = GetTickCount();
	}

	EVENTMSG GetCurrentMessage()
	{
		EVENTMSG msg = messages.at(message_index);

		DWORD message_playback_time = GetLastMessagePlaybackTime(); // That is the starting point
		
		if (!playback_options.normal_speed)
		{
			message_playback_time += playback_options.user_defined_time_interval * GetNumberOfMessagesRead();
		}

		//Check whether user has selected normal speed or given his own speed
		if (playback_options.normal_speed || playback_options.add_to_recorded_time )
		{
			//If playing at normal speed or if time_interval is to be added to recorded time
			//add it with time from the stored message from file.
			message_playback_time += msg.time - GetLastMessageOffsetTime();
		}

		msg.time = message_playback_time;

		//playlog << GetTickCount() << "\t" << msg.time << "\t" << (msg.time-GetTickCount()) << std::endl;
		//playlog.flush();

		return msg;
	}

	bool IsCurrentMessageAvailable()
	{
		return (message_index < (messages.size()));
	}

	bool AtLastMessage()
	{
		return (message_index == (messages.size() - 1));
	}

	DWORD GetLastMessageOffsetTime()
	{
		return HasPreviousMessage() ? previous_message.time : 0;
	}

	DWORD GetLastMessagePlaybackTime()
	{
		return previous_message_play_time;
	}

	DWORD GetNumberOfMessagesRead() { return message_index + 1; }

	bool MoveNext()
	{
		RaisePlaybackProgress();
		previous_message = messages.at(message_index);

		// This is the time when the message was actually played back
		previous_message_play_time = GetTickCount();

		if (!AtLastMessage())
		{	
			message_index++;
			return true;
		}
		else
		{
			// Increment in the else clause too, otherwise IsCurrentMessageAvailable will
			// never return false, and playback will never stop.
			message_index++;
			current_repetition_index++;

			// If we have completed repeat_count repetitions, we're done
			// otherwise, we reinitialize everything and start from scratch again.
			if (current_repetition_index > playback_options.repeat_count)
			{
				return false;
			}
			else
			{
				Reinitialize();
				return true;
			}
		}
	}

	void RaisePlaybackProgress()
	{
		if (playback_progress_proc)
		{
			PLAYBACKPROGRESSINFO info = {};
			info.current_iteration_number = current_repetition_index;
			info.total_number_of_iterations = playback_options.repeat_count;
			info.current_message_number = message_index + 1;
			info.total_number_of_messages = messages.size();

			playback_progress_proc(info);
		}
	}

	PLAYBACKOPTIONS GetPlaybackOptions() { return playback_options; }

private:
	virtual void SessionStopped()
	{	
		if (playback_stopped_proc)
			playback_stopped_proc();

		g_pPlaybackSession = NULL;
		delete this;
	}

	bool HasPreviousMessage()
	{
		return message_index > 0;
	}
};